#!/usr/bin/env bash

if [[ 0 -eq `echo $0 | grep -c '^/'` ]]; then
    # relative path
    EXEC_PATH=$(dirname "`pwd`/$0")
else
    # absolute path
    EXEC_PATH=$(dirname "$0")
fi

cd $EXEC_PATH || exit 1

############################
#    Linux:                #
#        ip netns ...      #
#    FreeBSD:              #
#        qjail ...         #
############################

OSNAME=`uname -s`
LIMIT=768

if [[ "" == $1 ]]; then
    printf "\x1b[31;01mWarning:\x1b[00m NO network interface given! auto detecting...\n"
    if [[ "Linux" == $OSNAME ]]; then
        IF=`ip l |
            perl -ane 'if($_=~/^\d+:\s*(\w+)(?=:)/){print("$1|\n");}' |
            grep -Ev 'lo|sit' |
            perl -p -e 's/\s+//g' |
            perl -p -e 's/\|/\n/g' |
            head -1` || exit 1
    else
        IF=`ifconfig -a |
            perl -ane 'if($_=~/^(\w+)(?=:)/){print("$1|\n");}' |
            grep -Ev 'lo|sit' |
            perl -p -e 's/\s+//g' |
            perl -p -e 's/\|/\n/g' |
            head -1` || exit 1
    fi
else
    IF=$1
fi

declare -A IPMAP=()

IP_0=10
IP_1=
IP_2=
IP_3=

# 10.[1..254].[1..254].[1..254]
IP_gen() {
    IP_1=$[1 + $RANDOM % 254]
    IP_2=$[1 + $RANDOM % 254]
    IP_3=$[1 + $RANDOM % 254]
}

linux() {
    # FOR seperate datadir
    home_path="/tmp/meth/linux/home"
    mkdir -p $home_path || exit 1

    # FOR netns
    inner_ifname="veth"

    # generate random IPs
    for((i=0;i<$LIMIT;i++)); do
        IP_gen
        key="${IP_0}_${IP_1}_${IP_2}_${IP_3}"
        if [[ "1" == ${IPMAP[${key}]} ]]; then
            let i-=1
        else
            IPMAP["$key"]="1"
        fi
    done

    # delete all old netns
    ip -a netns del

    # create new namespaces
    for IP in `echo ${!IPMAP[@]}`; do
        # different binary-symlink for each NS
        ln -svf /tmp/meth/parity /tmp/meth/parity$IP || exit 1
        ln -svf /tmp/meth/geth /tmp/meth/geth$IP || exit 1

        # IPC: unix-socket path
        rm -rf ${home_path}/${IP}
        mkdir -p ${home_path}/${IP} || exit 1

        # netns
        ip netns add $IP || exit 1

        ip l add l $IF name $inner_ifname type ipvlan mode l3
        if [[ 0 -ne $? ]]; then
            ip l del $inner_ifname
            ip l add l $IF name $inner_ifname type ipvlan mode l3 || exit 1
        fi

        ip l set $inner_ifname netns $IP || exit 1

        ip netns exec $IP bash -c "
            ip l set lo up &&
            ip l set $inner_ifname up &&
            ip r add default dev $inner_ifname &&
            ip a add `echo $IP | sed 's/_/\./g'` dev $inner_ifname &&
            tc qdisc add dev $inner_ifname root netem
        " || exit 1
    done

    # DO NOT replace '_' with '.' on linux
    # store keys ONLY, they are 'space-seperated' items
    # MUST add one space at last!!!
    printf "${!IPMAP[*]}" > /tmp/meth/____addr.list
    printf " " >> /tmp/meth/____addr.list
}

freebsd() {
    # generate random IPs
    for((i=0;i<$LIMIT;i++)); do
        IP_gen
        key="${IP_0}_${IP_1}_${IP_2}_${IP_3}"
        if [[ "1" == ${IPMAP[$key]} ]]; then
            let i-=1
        else
            IPMAP[$key]="1"
        fi
    done

    # delete all old jails
    qjail delete -A || exit 1

    # Completely delete the all old files created by jail
    rm -rf /usr/jails
    rm -rf /usr/local/etc/qjail.local
    rm -rf /usr/local/etc/qjail.global
    rm -rf /usr/local/etc/qjail.config
    rm -rf /usr/local/etc/qjail.packages
    rm -rf /usr/local/etc/qjail.fstab
    rm /var/log/jail_*
    rm /var/log/jails.lo*

    # create new jails
    for IP in `echo ${!IPMAP[@]}`; do
        qjail create -n $IF -4 `echo $IP | sed 's/_/\./g'` $IP || exit 1
    done

    # store keys ONLY, they are 'space-seperated' items
    # MUST add one space at last!!!
    printf "${!IPMAP[*]}" | sed 's/_/\./g' > /tmp/meth/____addr.list
    printf " " >> /tmp/meth/____addr.list
}

#####################################################################
#####################################################################

# prepare base path
mkdir -p /tmp/meth || exit 1

if [[ "Linux" == $OSNAME ]]; then
    linux
elif [[ "FreeBSD" == $OSNAME ]]; then
    freebsd
else
    printf "\x1b[31;01mUnsupported platform!\x1b[00m\n"
    exit 1
fi
